#!/usr/bin/env python
#------------------------------------------------------------------------------
#   Portions are Copyright 2009 Jim Storch
# 
#   CodenamedZero Server Code
#
#------------------------------------------------------------------------------


from miniboa import TelnetServer
import hashlib, time

#==============
#   Classes
#==============

class Item:

    def __init__(self, desc, place = "misc", keywords = None, value = 0, id = 0):
        self.desc = desc
        self.place = place
        if keywords is None:
            keywords = []
            self.keywords = keywords
        else:
            self.keywords = keywords
        self.id = id
        self.value = value

class Inventory:
    def __init__(self, items = None, wallet = 0):
        if items is None:
            items = []
            self.items = items
        else:
            self.items = items
        self.wallet = wallet
    def get_items(self):
        return self.items

class Player:   
    
    # Player Class, NOT TO BE CONFUSED WITH CLIENT
    # Use this to store details about the player

    def __init__(self, user, passwd, online = False, desc = "", inven = None, wear = None, gender = 'm', age = 18, room = 0, wallet = 0):
        self.user = user
        self.passwd = passwd
        self.desc = desc
        if inven is None:
            inven = Inventory()
            self.inven = inven
        else:
            self.inven = inven
        self.room = room        # Room = RoomID of room when last shutdown
        if wear is None:
            wear = dict()
            self.wear = wear
        else:
            self.wear = wear
        self.gender = gender
        self.age = age
        self.inven.wallet = wallet
        self.online = online
    
    def is_online(self):
        return self.online
    
    def get_user(self):
        return self.user
    
    def get_pass(self):
        return self.passwd

class Room:
    def __init__(self, name, desc, exits = None, id = 0, items = None):
        self.name = name
        self.desc = desc
        if exits is None:
            exits = dict()
            self.exits = exits
        else:
            self.exits = exits
        self.id = id
        if items is None:
            items = []
            self.items = items
        else:
            self.items = items
    
    def get_desc(self):
        return self.desc
    
    def get_name(self):
        return self.name
    
    def get_id(self):
        return self.id  
        
    def get_exits(self):
        return self.exits
        
    def get_items(self):
        return self.items

class WMap:
    
    # Map and Player Locations Class
    
    locations = []      # Identifier = PlayerID, Value = RoomID
    
    def __init__(self, rooms = None):
        if rooms is None:
            rooms = []
            self.r_list = rooms
        else:
            self.r_list = rooms

class Shop:
    def __init__(self, items = None, room = 0):
        if items is None:
            self.items = []
        else:
            self.items = items
        self.room = room

#=============#
# Constants
#=============#

EQUIP_LOC = ['misc', 'hat', 'hair', 'ear', 'neck', 'back', 'shoulder','torso', 'arm', 'wrist', 'hands', 'finger', 'undertorso',  'underwear', 'legs', 'socks', 'shoes', 'other']

STATIC_ID = 0

IDLE_TIMEOUT = 300 # Useless Right now

LAST_SYNC = 0

SYNC_TIME = 600

title = open('title', 'r') # Holds the Login Header
tstr = title.read()

playerf = 'users' # Holds login info and eventually room, description, and item details
itemf = 'items' # Holds login info and eventually room, description, and item details
shopf = 'shops'


PLAYER_LIST = [] # Holds all saved info for players
CLIENT_LIST = [] # Holds all currently connected clients
ITEM_LIST   = [] # Holds all Items loaded
SHOP_LIST   = [] # Holds all Shops

WORLD_MAP = WMap()

SERVER_RUN = True # Makes shit go


#===============#
# Methods
#===============#

def load_players():
    
    # Method that loads all login info from users file
    
    f = open(playerf, 'r')
    lnum = 0
    items = []
    desc = ""
    inven = Inventory()
    wearing = dict()
    wearbuff = []
    pbuff = []
    for line in f:
        sbuff = line.rstrip()
        pbuff.append(sbuff)
        lnum += 1
        if lnum % 9 == 3:
            for l in pbuff[-1].split():
                if l == '!n':
                    desc += "\n"
                else:
                    desc += l + " "
        if lnum % 9 == 4:
            for i in pbuff[-1].split():
                inven.items.append(ITEM_LIST[int(i)])
            #print inven.items
        if lnum % 9 == 5:
            for i in pbuff[-1].split():
                wearbuff = i.split(":")
                wearing[wearbuff[0]] = int(wearbuff[1])
            #print wearing
        if lnum % 9 == 0: 
            playload = Player(pbuff[-9], pbuff[-8], False, desc, inven, wearing, pbuff[-4], int(pbuff[-3]), int(pbuff[-2]), int(pbuff[-1]) )
            PLAYER_LIST.append(playload)
            print (pbuff[-9] + ", " + pbuff[-8] + " Loaded.") # Load Check
            print ("%s Items in inventory." % len(playload.inven.items) )
            items = []
            inven = Inventory()
            wearing = dict()
            wearbuff = []
    print("%s players loaded." % len(PLAYER_LIST)) # Final load check
    f.close()

def load_items():
    
    # Method that loads all Items from items file
    
    global STATIC_ID
    f = open(itemf, 'r')
    lnum = 0
    ibuff = []
    for line in f:
        sbuff = line.rstrip()
        ibuff.append(sbuff) 
        lnum += 1
        if lnum % 4 == 0: # Every three lines takes the info and makes a item with it
            itemload = Item(ibuff[-4], ibuff[-3], ibuff[-2].split(), int(ibuff[-1]), STATIC_ID)
            STATIC_ID += 1
            ITEM_LIST.append(itemload)
            print (ibuff[-4] + " Loaded.") # Load Check
            
    print("%s Items loaded." % len(ITEM_LIST)) # Final load check
    f.close()

def load_shops():
    
    # Method that loads all Items from items file
    
    f = open(shopf, 'r')
    lnum = 0
    ibuff = []
    for line in f:
        sbuff = line.rstrip()
        ibuff.append(sbuff) 
        lnum += 1
        if lnum % 2 == 0: # Every three lines takes the info and makes a item with it
            shopload = Shop(ibuff[-2].split(), int(ibuff[-1]) )
            SHOP_LIST.append(shopload)
            print ("Shop in room #" + ibuff[-1] + " Loaded.") # Load Check
            
    print("%s Shops loaded." % len(SHOP_LIST)) # Final load check
    f.close()

def sync_player(client):
    
    # Syncs an online client with their player file that's currently loaded
    
    for player in PLAYER_LIST:
        if client.mode == 10:
            if player.user == client.username:
                player.passwd = client.passwordatmpt
                player.desc = client.description
                player.inven = client.inventory
                player.wear = client.wearing
                player.room = WORLD_MAP.locations[client.id]
                player.gender = client.gender
                player.age = client.age
                print(player.user + " synced correctly.")

def sync_players():
    
    # Syncs all clients with their individual player files
    
    for client in CLIENT_LIST:
        sync_player(client)

def setup_map():
    
    # Placeholder method, only here to make a map until I make a map file.
    
    greetingroom = Room("Greeting Hall", "The Place of Giants.", {'w': 1}, 0, [ITEM_LIST[0]] )
    otherroom = Room("Hallway", "The fucking hallway, asshole.", {'e': 0}, 1)
    ROOM_LIST = [greetingroom, otherroom]
    WORLD_MAP.r_list = ROOM_LIST

def save_player(username, password, gender, age):
    
    # Mainly used to save new characters, appends on to bottom of file
    
    f = open(playerf, 'a')
    f.write(username + "\n")
    f.write(password + "\n")
    f.write("\n\n\n")
    f.write(gender +"\n")
    f.write("%s\n" % age)
    f.write("0\n")
    f.close()

def save_all_players():
    
    # Saves all loaded player files, updating with the information from last sync
    
    f = open(playerf, 'w')
    for player in PLAYER_LIST:
        f.write(player.user + "\n")
        f.write(player.passwd + "\n")
        for l in player.desc.splitlines():
            f.write(l + " !n ")
        f.write("\n")
        for i in player.inven.items:
            f.write("%s " % i.id)
        f.write("\n")
        for k in player.wear.keys():
            f.write(k + ":%s " % player.wear[k])
        f.write("\n" + player.gender)
        f.write("\n%s\n" % player.age)
        f.write("%s\n" % player.room)
        f.write("%s\n" % player.inven.wallet)

    f.close()

def get_exits(room):
    
    # Returns a string list of exits for any given room in wmap
    
    streturn = "^GExits: "
    keys = room.exits.keys()
    for key in keys:
        streturn += "^g%s: %s," % (key, WORLD_MAP.r_list[room.exits[key]].get_name()) # I.E. "e: The Great Room, nw: The Shit Room"
    if keys == []:
        streturn += "None" # No Exits? Return a placeholder.
    else:
        streturn = streturn[:len(streturn) - 1]
    streturn += ".\n"
        
    return streturn

def new_item(desc, itype, keywords, value):
    
    # Builder for new items outside of the load sequence
    
    global STATIC_ID
    
    item = Item(desc, itype, keywords, value, STATIC_ID)
    STATIC_ID += 1
    
    f = open(itemf, 'a')
    f.write(desc + "\n")
    f.write(itype + "\n")
    for k in keywords:
        f.write(k + " ")
    f.write("\n%s\n" % value)
    f.close()
    
    ITEM_LIST.append(item)
    return item

def parse_items(items):
    
    # Returns a string of items, similar to get_exits
    
    streturn = ""
    for item in items:
        streturn += item.desc + ",\n"
    if items == []:
        streturn = "^rNothing.\n"
    else:
        streturn = streturn.rstrip(',\n')
        streturn += ".\n\n"
    return streturn

def parse_wear(client, wearing):
    
    # Returns a string of items, similar to get_exits
    
    streturn = ""
    for wnum in wearing:
        streturn += "^g[%s]^d " % ITEM_LIST[client.wearing[wnum]].place
        streturn += ITEM_LIST[client.wearing[wnum]].desc + ",\n"
    if wearing == dict():
        streturn = "^rNothing.\n"
    else:
        streturn = streturn.rstrip(',\n')
        streturn += ".\n\n"
    return streturn

def get_players_in_room(client):
    
    # Really memory wasteful location search function, probably needs to be rewritten
    
    streturn = "^YPlayers here:^y "
    found = False
    for player in CLIENT_LIST:
        if player.mode == 10:
            if player != client and WORLD_MAP.locations[player.id] == WORLD_MAP.locations[client.id]:
                found = True
                streturn += "%s " % player.username.capitalize()
    
    if found == False:
        streturn += "Nobody."
    
    streturn += "\n"
    return streturn

def look(client, arg = "look"):
    
    # Standard Look Function, lists room, room desc, players, exits, and items in the room
    
    if len(arg) == 4:
        rid = WORLD_MAP.locations[client.id]
        for room in WORLD_MAP.r_list:          # Memory Intensive/ Wasteful, needs to be rewritten
            if rid == room.get_id():
                lookr = room
                break
        client.send_cc(lookr.get_name() + "\n" + lookr.get_desc() + "\n" + get_exits(lookr) + get_players_in_room(client) + "^RItems in the area:\n" + parse_items(lookr.items) + "^d^.^u" )
    else:
        found = False
        for guest in CLIENT_LIST:
            if WORLD_MAP.locations[guest.id] == WORLD_MAP.locations[client.id] and arg[5:] == guest.username:
                found = True
                client.send_cc("^GYou see " + guest.username.capitalize() + ".^d^.^u\n" + guest.description + "^d^.^u\n")
                client.send_cc("^RThey have in their posession:\n^d^.^u" + parse_items(guest.inventory.items))
                client.send_cc("^RThey are wearing:\n^d^.^u" + parse_wear(guest,guest.wearing))

def shop(client):
    
    # Standard Look Function, lists room, room desc, players, exits, and items in the room
    
    rid = WORLD_MAP.locations[client.id]
    shopwanted = -1
    for s in SHOP_LIST:          # Memory Intensive/ Wasteful, needs to be rewritten
        if rid == s.room:
            shopwanted = s
            break
    if shopwanted != -1:
        output = "^gWelcome to our Shop!\n\nItems Available:\n^d^.^u"
        if len(shopwanted.items) > 0:
            for inum in shopwanted.items:
                output += "^g$%4.2f^d^.^u, %s^d^.^u,\n" % (ITEM_LIST[int(inum)].value, ITEM_LIST[int(inum)].desc)
            output = output.rstrip(",\n")
            output += ".\n\n"
        else:
            output += "^rNothing.\n\n^d^.^u"
        client.send_cc(output)
    else:
        client.send_cc("^rThis command only works if you are in a shop.\n^d^.^u")

def buy(client, cmd):
    
    # Standard Look Function, lists room, room desc, players, exits, and items in the room
    
    rid = WORLD_MAP.locations[client.id]
    found = False
    shopwanted = -1
    for s in SHOP_LIST:          # Memory Intensive/ Wasteful, needs to be rewritten
        if rid == s.room:
            shopwanted = s
            break
    if shopwanted != -1:
        if len(shopwanted.items) > 0:
            for inum in shopwanted.items:
                for k in ITEM_LIST[int(inum)].keywords:
                    if k == cmd[4:]:
                        found = True
                        founditem = ITEM_LIST[int(inum)]
                        break
                if found == True:
                    break
            if found == True:
                if client.inventory.wallet >= founditem.value:
                    client.inventory.wallet -= founditem.value
                    client.inventory.items.append(founditem)
                    client.send_cc("You bought up " + founditem.desc + "^d^.^u\n")
                    client.send_cc("^g$%4.2f has been deducted from your account.^d^.^u\n" % founditem.value)
                else:
                    client.send_cc("^rYou don't have enough money for that item.^d^.^u\n")
            else:
                client.send_cc("^rThat item isn't present in this store.^d^.^u\n")
        else:
            client.send_cc("^rThere are no items at this shop.^d^.^u\n")
    else:
        client.send_cc("^rThis command only works if you are in a shop.\n^d^.^u")

def broadcast(msg):
    
    # Abusive Command that should be trashed, will do later.
    
    for client in CLIENT_LIST:
        client.send_cc(msg)

def chat(client, txt):
    
    # Basic talk function, accepts both ' or say as well as whatever they want to say
    
    if txt[:3] == "say":
        msg = txt[4:]
    else:
        msg = txt[1:]
        
    print '%s says, "%s" in Room#%s' % (client.username.capitalize(), msg, WORLD_MAP.locations[client.id] )

    for guest in CLIENT_LIST:
        if guest != client and WORLD_MAP.locations[guest.id] == WORLD_MAP.locations[client.id]:
            guest.send_cc('%s says, "%s"\n' % (client.username.capitalize(), msg))
        elif guest == client:
            guest.send_cc('You say, "%s"\n' % msg)
    
def emote(client, txt):
    
    # Basic talk function, accepts both ' or say as well as whatever they want to say
    
    if txt[:5] == "emote":
        msg = txt[6:]
    else:
        msg = txt[1:]
        
    print '%s %s (in Room#%s)' % (client.username.capitalize(), msg, WORLD_MAP.locations[client.id] )

    for guest in CLIENT_LIST:
        if guest != client and WORLD_MAP.locations[guest.id] == WORLD_MAP.locations[client.id]:
            guest.send_cc('%s %s\n' % (client.username.capitalize(), msg))
        elif guest == client:
            guest.send_cc('%s %s\n' % (client.username.capitalize(), msg))

def move(client, dir):
    
    # Move function, moves the player in the direction desired if said direction exists
    # Also alerts all other users in both rooms where the movement occurred
    
    broom = WORLD_MAP.r_list[WORLD_MAP.locations[client.id]]
    prevl = WORLD_MAP.locations[client.id]
    if dir in broom.get_exits():
        WORLD_MAP.locations[client.id] = broom.get_exits()[dir]
        
        for player in CLIENT_LIST:
            if WORLD_MAP.locations[player.id] == prevl:
                player.send_cc("%s left in the %s exit.\n" % (client.username.capitalize(), dir) )
            elif WORLD_MAP.locations[player.id] == WORLD_MAP.locations[player.id] and player != client:
                player.send_cc("%s entered from the %s exit.\n" % (client.username.capitalize(), dir) )
            elif player == client:
                client.send_cc("You moved in the %s exit.\n" % dir)
        look(client)
    else:
        client.send_cc("That exit doesn't exist, sorry.\n")
    
def pickup(client, item):
    room = WORLD_MAP.r_list[WORLD_MAP.locations[client.id]]
    found = False
    for i in room.items:
        for k in i.keywords:
            if k == item[7:]:
                room.items.remove(i)
                client.inventory.items.append(i)
                for p in CLIENT_LIST:
                    if WORLD_MAP.locations[p.id] == WORLD_MAP.locations[client.id] and client != p:
                        p.send_cc("%s picked up %s.\n" % (client.username.capitalize(), i.desc) )
                    elif client == p:
                        p.send_cc("You picked up %s\n" % (i.desc) )
                found = True
                break
        if found == True:
            break
    if found == False:
        client.send_cc("We're sorry, that item was not able to be found.\n")

def drop(client, item):
    room = WORLD_MAP.r_list[WORLD_MAP.locations[client.id]]
    found = False
    for i in client.inventory.items:
        for k in i.keywords:
            if k == item[5:]:
                client.inventory.items.remove(i)
                room.items.append(i)
                for p in CLIENT_LIST:
                    if WORLD_MAP.locations[p.id] == WORLD_MAP.locations[client.id] and client != p:
                        p.send_cc("%s dropped %s.\n" % (client.username.capitalize(), i.desc) )
                    elif client == p:
                        p.send_cc("You dropped up %s\n" % (i.desc) )
                found = True
                break
                break
    if found == False:
        client.send_cc("We're sorry, that item was not able to be dropped.\n")
    
def inv(client):
    client.send_cc("^GWallet: $%s.00\n\n^RYou currently have in your inventory:^d^.^u\n" % client.inventory.wallet)
    streturn = ""
    for i in client.inventory.items:
        streturn += i.desc + "^d^.^u,\n"
    if client.inventory.items == []:
        streturn += "^rNothing.^d^.^u\n"
    else:
        streturn = streturn.rstrip(",\n")
        streturn += "^d^.^u.\n\n"
    client.send_cc(streturn)

def give(client, cmd):
    room = WORLD_MAP.r_list[WORLD_MAP.locations[client.id]]
    fail = False
    if len(cmd[5:].split()) > 0:
        item = cmd[5:].split()[0].lower()
    else:
        fail = True
    if len(cmd[5:].split()) > 1:
        reciever = cmd[5:].split()[1].lower()
    else:
        fail = True
    found = False
    if fail == False:
        for i in client.inventory.items:
            for k in i.keywords:
                if k == item:
                    for p in CLIENT_LIST:
                        if p.username == reciever and WORLD_MAP.locations[p.id] == WORLD_MAP.locations[client.id]:
                            client.inventory.items.remove(i)
                            p.inventory.items.append(i)
                            client.send_cc("You gave %s.\n" % (i.desc) )
                            p.send_cc("%s recieved %s.\n" % (p.username.capitalize(), i.desc) )
                            found = True
                            break
                if found == True:
                    break
            if found == True:
                break
    if found == False:
        client.send_cc("We're sorry, that item was not able to be given.\n")

def take(client, cmd):
    room = WORLD_MAP.r_list[WORLD_MAP.locations[client.id]]
    fail = False
    if len(cmd[5:].split()) > 0:
        item = cmd[5:].split()[0].lower()
    else:
        fail = True
    if len(cmd[5:].split()) > 1:
        takee = cmd[5:].split()[1].lower()
    else:
        fail = True
    found = False
    
    for p in CLIENT_LIST:
        if p.username == takee:
            break
    
    if fail == False:
        for i in p.inventory.items:
            for k in i.keywords:
                if k == item:
                    if p.username == takee and WORLD_MAP.locations[p.id] == WORLD_MAP.locations[client.id]:
                        p.inventory.items.remove(i)
                        client.inventory.items.append(i)
                        client.send_cc("You took %s.\n" % (i.desc) )
                        p.send_cc("%s was taken away.\n" % (i.desc) )
                        found = True
                        break
                if found == True:
                    break
            if found == True:
                break
    if found == False:
        client.send_cc("We're sorry, that item was not able to be taken.\n")

def design_item(client, msg):
    
    # Design function for new items accepting a string of arguments
    # design "<desc>" <place> <keywords> [$value]
    
    # TODO: Make an approval system for new items.
    
    rippedstr = msg.split()
    fail = False
    mode = 0
    desc = ""
    place = ""
    keywords = []
    value = 0
    for s in rippedstr:
        if s[0] == '"' and mode == 0:
            mode = 1
        if mode == 1:
            if s[0] == '"':
                desc += s[1:] + " "
            elif s[-1] == '"':
                desc += s[:-1]
            else:
                desc += s + " "
            
            if s[-1] == '"' and s != rippedstr[1]:
                mode = 2
                continue
        if mode == 3:
            if s[0] == '$':
                value = int(s[1:])
                break
            keywords.append(s)
        if mode == 2:
            place = s
            mode = 3
    
    if mode < 3 or keywords == []:
        client.send_cc('^d^.^uDesign failed. Check your syntax.\n\nDesigns should take the form: \ndesign "<desc>" <place> <keyword 1>[ <keyword 2> <etc.>] $[value]')
    else:
        nitem = new_item(desc, place, keywords, value)
        client.inventory.items.append(nitem)
        client.send_cc("You picked up " + nitem.desc + "^d^.^u.\n")

def wear (client, cmd):
    found = False
    overw = False
    for i in client.inventory.items:
        for k in i.keywords:
            if k == cmd[5:]:
                for wearingk in client.wearing.keys():
                    if wearingk == i.place:
                        client.inventory.items.remove(i)
                        client.send_cc("You take off " + ITEM_LIST[client.wearing[wearingk]].desc)
                        client.inventory.items.append(ITEM_LIST[client.wearing[wearingk]])
                        client.wearing[i.place] = i.id
                        overw = True
                        client.send_cc("^d^u^. and you put on " + i.desc + "^d^u^. in your " + i.place + " slot.^d^u^.\n\n")
                if overw != True:
                    client.inventory.items.remove(i)
                    client.wearing[i.place] = i.id
                    client.send_cc("You put on " + i.desc +"^d^u^. in your " + i.place + " slot.\n\n")
                found = True
                break
        if found == True:
            break
    if found == False:
        client.send_cc("We're sorry, that item was not able to be equipped.\n")

def takeoff (client, cmd):
    found = False
    for k in client.wearing.keys():
        for itemk in ITEM_LIST[int(client.wearing[k])].keywords:
            if cmd[8:] == itemk:
                client.inventory.items.append(ITEM_LIST[int(client.wearing[k])])
                del client.wearing[k]
                client.send_cc("You took off " + client.inventory.items[-1].desc + " from your " + client.inventory.items[-1].place + " slot.\n\n")
                found = True
                break
        if found == True:
            break

    if found == False:
        client.send_cc("We're sorry, that item was not able to be equipped.\n")

def do_command(client):

    # Main Command Method, Figures out how to accept your command.

    global SERVER_RUN
    msg = client.get_command()
    cmd = msg.lower()
    client.send_cc("\n")
    if cmd == 'bye':
        client.active = False
    elif cmd == 'shutdown':
        SERVER_RUN = False
    elif cmd[:5] == 'look ':
        look(client, cmd)
    elif cmd[:4] == 'say ' or cmd[:1] == "'":
        chat(client, msg)
    elif cmd[:6] == 'emote ' or cmd[:1] == ",":
        emote(client, msg)
    elif cmd == "e" or cmd == "w" or cmd == "s" or cmd == "n" or cmd == "se" or cmd == "ne" or cmd == "sw" or cmd == "nw" or cmd == "u" or cmd == "d":
        move(client, cmd)
    elif cmd[:7] == "pickup ":
        pickup(client, cmd)
    elif cmd[:5] == "drop ":
        drop(client, cmd)
    elif cmd[:5] == "give ":
        give(client, cmd)
    elif cmd[:5] == "take ":
        take(client, cmd)
    elif cmd[:7] == "design ":
        design_item(client, msg)
    elif cmd == "sync":
        sync_players()
    elif cmd == "inv":
        inv(client)
    elif cmd == "save":
        save_all_players()
    elif cmd == "shop":
        shop(client)
    elif cmd[:4] == "buy ":
        buy(client, cmd)
    elif cmd[:5] == "wear ":
        wear(client, cmd)
    elif cmd[:8] == "takeoff ":
        takeoff(client, cmd)
    elif cmd == "descedit":
        client.mode = 11
        client.send_cc("^y||=====================||\n")
        client.send_cc("||     Welcome  to     ||\n")
        client.send_cc("||   Decription Edit   ||\n")
        client.send_cc("||=====================||\n\n")
        client.send_cc("Enter any line to add to your description.\nEnter !q to return to game mode.\nEnter !l to look at your description so far.\nEnter !dl to delete last line.\nEnter !d to delete your description completely.\nEnter !r to repeat the dialog.\n\nYour Description at the moment:\n^d^.^u")
        client.send_cc(client.description)
    else:
        client.send_cc("The command you submitted is not recognizable. Check your privilege.\n")

#================#
# Connections
#================#
   
def on_connect(client):
    
    # New Connection Method, handles new clients
    
    print "++ Opened connection to %s" % client.addrport()
    client.request_naws()
    client.send_cc(tstr)
    
    client.mode = 1 # Awaiting username
    
    CLIENT_LIST.append(client)
    
    client.send_cc("^YPlease Enter Username: ")
    
def on_disconnect(client):
    
    # Connection Closing Method, handles disconnections
    # Fixes the client list, make sure everything remains stable without the client
    # Also tells the player list that the user is now offline (will allow others to sign in under that name once again)
    print "-- Lost connection to %s" % client.addrport()
    if client.mode == 10:
        print "-- aka %s" % client.username.capitalize()
        sync_player(client)
        WORLD_MAP.locations.pop(client.id)
        for c in CLIENT_LIST:
            if c.id > client.id:
                c.id -= 1
        for player in PLAYER_LIST:
            if player.user == client.username:
                player.online = False
                break
            
        broadcast('%s left the MUD.\n' % client.username.capitalize() )
    CLIENT_LIST.remove(client)

### KICK SILENCED BECAUSE UNNECESSARY ATM

"""
def kick_idle():
    
    ### Looks for idle clients and disconnects them by setting active to False.
    
    ## Who hasn't been typing?
    for client in CLIENT_LIST:
        if client.idle() > IDLE_TIMEOUT:
             print('-- Kicking idle lobby client from %s' % client.username.capitalize())
            client.active = False
"""
"""
def sync():
    
    
    if LAST_SYNC == 0:
        LAST_SYNC = time.time()
    if time.time >= SYNC_TIME + LAST_SYNC:
        sync_players()
        LAST_SYNC = time.time()
"""
def process_clients():
    
    #-------------------------#
    # Main Processor of Input
    #-------------------------#
    #
    # Sends your input to the proper section, depending upon what mode the user is in
    # Handles New User Login, Existing User Login, and General Input
    # Also handles description edits
    #
    
    
    for client in CLIENT_LIST:
        if client.cmd_ready:
            if client.mode == 11:
                msg = client.get_command()
                cmd = msg.lower()
                if cmd == "!q":
                    client.mode = 10
                    client.send_cc("^yReturning to normal mode.^d^.^u\n")
                    continue
                elif cmd == "!l":
                    client.send_cc("^yYour description so far:^d^.^u\n")
                    client.send_cc(client.description)
                elif cmd == "!d":
                    client.send_cc("^yType !deleteall to delete your description.^d^.^u\n")
                elif cmd == "!deleteall":
                    client.description = ""
                    client.send_cc("^yDescription Deleted.^d^.^u\n")
                elif cmd == "!dl":
                    temp = client.description.splitlines(True)
                    if temp != []:
                        temp.pop()
                    client.description = ""
                    for l in temp:
                        client.description += l
                    client.send_cc("^yLast line deleted.^d^.^u\n")
                elif cmd == "!r":
                    client.send_cc("^y||=====================||\n")
                    client.send_cc("||     Welcome  to     ||\n")
                    client.send_cc("||   Decription Edit   ||\n")
                    client.send_cc("||=====================||\n\n")
                    client.send_cc("Enter any line to add to your description.\nEnter !q to return to game mode.\nEnter !l to look at your description so far.\nEnter !dl to delete last line.\nEnter !d to delete your description completely.\nEnter !r to repeat the dialog.\n\nYour Description at the moment:\n^d^.^u")
                    client.send_cc(client.description)
                else:
                    client.description += msg + "\n"
                    client.send_cc("^yLine added.^d^.^u\n")
                
            if client.mode == 10:
                
                # GENERAL MODE
                # If you're already signed in, just send input to the command processor
                
                do_command(client)
                
            elif client.mode == 1:
                
                # Just Connected, accepts the Username, Sends you to password Stage
                
                client.username = client.get_command().lower()
                client.password_mode_on()
                client.mode = 2
                print("Client input: " + client.username)
                client.send_cc("Please Enter Password: ")
            elif client.mode == 2:
                
                # Password Stage
                #
                # * Handles New Users if Username doesn't exist
                # * Handles Existing Users
                #   - If Password matches, put them in normal mode and enter them
                #     first room
                #   - If the Password does not match, restart them from the first step
                #
                
                client.passwordatmpt = client.get_command()                
                client.passwordatmpt = hashlib.sha256(client.passwordatmpt).hexdigest()
                print ("Client input: " + client.passwordatmpt)
                found = False
                for player in PLAYER_LIST:
                    if player.get_user() == client.username and player.get_pass() == client.passwordatmpt and player.is_online() == False:
                        
                        # Checks Username, Pass, and that the user isn't online
                        # Then Accepts the user
                        
                        found = True
                        client.send_cc("Welcome " + client.username.capitalize() + "!\n\n")
                        client.mode = 10     # Add the User to General Mode
                        client.inventory = player.inven
                        client.wearing = player.wear
                        client.description = player.desc
                        client.gender = player.gender
                        client.age = player.age
                        WORLD_MAP.locations.append(player.room)     # Put the user on the world map
                        client.id = len(WORLD_MAP.locations) - 1    # Give the user the right ID
                        player.online = True # Don't allow others to login under this name
                        broadcast('^d^.^u%s joined.\n\n' % client.username.capitalize() ) # Tell everyone they're here
                        look(client) # Show the User what room they're now in
                        break
                    if player.get_user() == client.username and player.get_pass() == client.passwordatmpt and player.is_online() == True:
                        
                        # User is already connected, deny the login
                        
                        found = True
                        client.send_cc("We're sorry, that user is connected already, please try again.\n\nPlease Enter Username: ")
                        client.mode = 1
                    if player.get_user() == client.username and player.get_pass() != client.passwordatmpt:
                        
                        # Password is wrong, deny the login
                        
                        found = True
                        client.send_cc("We're sorry, that password did not match ours, please try again.\n\nPlease Enter Username: ")
                        client.mode = 1
                        break
                if found == False:
                    
                    # It's a new user, put them in New User Setup
                    
                    client.send_cc("Enter Password Again: ")
                    client.mode = 3              
            elif client.mode == 3:
                
                # Get the password again to check to make sure the user knows their password
                # If good, ask if they're sure they want to create a character.
                # If not, send them to the beginning.
                
                client.passwordrepeat = client.get_command()
                client.passwordrepeat = hashlib.sha256(client.passwordrepeat).hexdigest()
                if client.passwordrepeat != client.passwordatmpt:
                    client.send_cc("Passwords did not match, please try again.\n\nPlease Enter Username: ")
                    client.mode = 1
                else:
                    client.send_cc("Is your character a boy or a girl? (M/F): ")
                    client.mode = 4
                    
            elif client.mode == 4:
                client.gender = client.get_command().lower()
                if client.gender == "m" or client.gender == "f":
                    client.send_cc("How old is your character? (Default is 18): ")
                    client.mode = 5
                else:
                    client.send_cc("We need you to submit a proper gender.\nAre you a boy or a girl? (M/F): ")
            elif client.mode == 5:
                try:
                    client.age = int(client.get_command())
                    if client.age <= 100 and client.age >= 0:
                        client.send_cc("Are you sure you want to create the character " + client.username.capitalize() + "? (Y/n): ")
                        client.mode = 6
                    else:
                        client.send_cc("Age must be between 0 and 100\nHow old is your character? (Default is 18): ")
                except ValueError:
                    client.send_cc("You didn't input an age, try again.\nHow old is your character? (Default is 18): ")
            elif client.mode == 6:
                
                # Final check step
                # If they really want in, save their info, add them to player list and put them in the first room
                # If not, start them over
                
                response = client.get_command().lower()
                if response == "y" or response == "":
                    player = Player(client.username.lower(), client.passwordatmpt, True)
                    PLAYER_LIST.append(player)
                    save_player(client.username, client.passwordatmpt, client.gender, client.age) 
                    client.send_cc("Welcome " + client.username.capitalize() + "!\n\n")
                    client.mode = 10
                    client.inventory = Inventory()
                    client.wearing = dict()
                    client.description = ""
                    WORLD_MAP.locations.append(0)
                    client.id = len(WORLD_MAP.locations) - 1
                    broadcast('^d^.^u%s joined.\n\n' % client.username.capitalize() )
                    look(client)
                    break
                elif response == "n":
                    client.send_cc("Alright, let's start over.\n\nPlease Enter Username: ")
                    client.mode = 1
                else:
                    client.send_cc("That isn't a requested answer, please try again.\n" \
                        "Are you sure you want join, " + client.username.capitalize() + "? (Y/n): ")

#------------------------------------------------------------------------------
#       Main
#------------------------------------------------------------------------------

if __name__ == '__main__':
    
    load_items()   # Load Items
    load_shops()
    load_players() # Load Player Login Info
    setup_map()
    
    telnet_server = TelnetServer(
        # Start up the MUD Server
        port=7777,
        address='',
        on_connect=on_connect,
        on_disconnect=on_disconnect,
        timeout = .05
        )

    print(">> Listening for connections on port %d.  CTRL-C to break."
        % telnet_server.port)

    ## Server Loop
    while SERVER_RUN: # Continue running till the cows come home
        telnet_server.poll()        ## Send, Recv, and look for new connections
        # kick_idle()
        # sync()
        process_clients()           ## Check for client input
    save_all_players()
    print(">> Server shutdown.")